#pragma once
#include <vector>
#include <ecrt.h>
#include <mutex>
#include <list>
#include <map>
#include <atomic>

#include "rtbus/rtbus.h"
namespace rtbus {
class ECatImpl;
class ECat : public RtCommuItf
{
public:
    struct Config
    {
        std::string adapter;           //硬件接口名称
        uint32_t taskcycle_us;         //主站通讯周期
        uint32_t check_slave_timeout;  //启动时检测从站的最长时间，default 30s
        bool active_dc;                //是否激活DC
        struct Slave
        {
            uint32_t position;         //从站位置
            uint32_t vendor_id;        //从站厂商ID
            uint32_t product_code;     //从站产品ID
            uint32_t revision_number;  //从站版本号
            int cycletime_us;          //从站通讯周期,同taskcycle_us
            int shifttime_us;          //从站通讯周期偏移时间
            struct Pdo
            {
                uint16_t index;
                struct Entry
                {
                    uint16_t index;
                    uint16_t subindex;
                    size_t bitsize;
                    uint32_t offset;
                };
                std::vector<Entry> entries;
            };
            Pdo txpdos;
            Pdo rxpdos;
        };
        std::vector<Slave> slave_config_;
    };

public:
    ECat();
    ~ECat() final;
    int open(RtCommuItf::BusCfg cfg) override;
    void close() override;
    int active() override;
    int deactive() override;
    int register_sdo_handle(uint8_t slave_id, uint32_t write_req_frame_id, uint32_t read_req_frame_id, uint32_t resp_frame_id, size_t obj_id_size) override;

    void send() override;
    void recv(int64_t* time_off) override;
    void reset() override;
    bool is_actived() override { return actived_flag_ != 0; }
    int get_sdo(uint8_t slave_id, uint32_t obj_id, std::function<int(uint8_t*, int)> cb, int timeout, int retry) override;
    int get_sdo_blocking(uint8_t slave_id, uint32_t objid, void* data, int data_len, int retry) override;
    int set_sdo(uint8_t slave_id, uint32_t obj_id, uint8_t val[4], size_t size, std::function<int(uint8_t*, int)> cb, int timeout, int retry) override;
    int set_sdo_blocking(uint8_t slave_id, uint32_t objid, void* data, int s, void* respdata, int retry) override;
    int config_slave(SlaveInfo& info) override;
    void sync_time(RtCommuItf* master) override;
    bool is_can() override { return false; }

public:
    int load_cfg(struct Config& cfg);

private:
    std::string find_esi_file(int vendor_id, int product_code);

private:
    struct DeviceDescInfo
    {
        int vendor_id;
        int product_code;
        int version_number;
        std::string esi_file;
    };
    std::vector<DeviceDescInfo> device_desc_;

    std::atomic_uint8_t actived_flag_;  // 0:未激活 1:激活中 2:激活完成
    Config cfg_;
    ECatImpl* impl_;
    int8_t iomap_[4096];
    std::string ifname;
    int64_t toff;
};
}  // namespace rtbus
